package com.suxin.shiro.jwt.config;

import com.suxin.shiro.cache.RedisCache;
import com.suxin.shiro.cache.RedisCacheManager;
import com.suxin.shiro.jwt.filter.JwtFilter;
import com.suxin.shiro.jwt.realm.JwtRealm;
import com.suxin.shiro.jwt.realm.UserModularRealmAuthenticator;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;

import javax.servlet.Filter;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Tang
 * @classname ShiroConfig
 * @description [  ]
 * @date 2021/3/21 11:01
 */
@Configuration
public class ShiroConfig {

    /**
     * 验证token
     * @param redisTemplate
     * @return
     */
    @Bean
    JwtRealm jwtRealm(RedisTemplate<String, Object> redisTemplate) {
        JwtRealm jwtRealm = new JwtRealm();
        // 开启缓存
        jwtRealm.setCacheManager(new RedisCacheManager(redisTemplate));
        jwtRealm.setCachingEnabled(true);
        jwtRealm.setAuthenticationCachingEnabled(true);
        jwtRealm.setAuthenticationCacheName("AuthenticationCache");
        jwtRealm.setAuthenticationCache(new RedisCache("AuthenticationCache",redisTemplate));

        jwtRealm.setAuthorizationCachingEnabled(true);
        jwtRealm.setAuthorizationCacheName("AuthorizationCache");
        jwtRealm.setAuthorizationCache(new RedisCache("AuthorizationCache",redisTemplate));
        return jwtRealm;
    }

    /**
     * realm选择器
     * 重写 ModularRealmAuthenticator doAuthenticate()
     * @return
     */
    @Bean
    UserModularRealmAuthenticator userModularRealmAuthenticator() {
        return new UserModularRealmAuthenticator();
    }


    /**
     * filter 设置
     * *常用的过滤器:
     * * anon: 无需认证(登录)可以访问
     * * authc:必须认证才可以访问
     * * user: 如果使用rememberMe的功能可以直按访间
     * * perms:该资源必须得到资源权限才可以访问
     * * role: 该资源必须得到角色权限才可以访问
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager,
                                                         RedisTemplate<String, Object> redisTemplate) throws Exception {
        Map<String, String> resourceHashMap = new LinkedHashMap<>(16);
        // 放行登录接口
        resourceHashMap.put("/user/login", "anon");
        resourceHashMap.put("/user/loginOut", "anon");
        resourceHashMap.put("/user/error", "anon");
        // authc:请求这个资源需要认证
//        resourceHashMap.put("/user/**","authc");

        // 使用我们自定义的filter处理
        resourceHashMap.put("/**", "jwtFilter");

        ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
        // 设置登录 url,没权限的时候跳转
        filterFactoryBean.setLoginUrl("/login.jsp");
        filterFactoryBean.setSuccessUrl("/**");
        // 没权限
        filterFactoryBean.setUnauthorizedUrl("/user/error");
        filterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        filterFactoryBean.setFilterChainDefinitionMap(resourceHashMap);
        // 自定义filter
        Map<String, Filter> filterHashMap = new LinkedHashMap<>(16);
        filterHashMap.put("jwtFilter", new JwtFilter(redisTemplate));
        filterFactoryBean.setFilters(filterHashMap);
        return filterFactoryBean;
    }

    /**
     * 权限管理器设置
     * @return
     */
    @Bean
    DefaultWebSecurityManager defaultWebSecurityManager(RedisTemplate<String, Object> redisTemplate) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        List<Realm> realmList = Collections.singletonList(
                jwtRealm(redisTemplate)
        );
        // 为 SecurityManager 添加 Realm
        securityManager.setRealms(realmList);
        userModularRealmAuthenticator().setRealms(realmList);
        // 设置realm选择器
        securityManager.setAuthenticator(userModularRealmAuthenticator());

        // 关闭shiro自带的session
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        securityManager.setSubjectDAO(subjectDAO);
        return securityManager;
    }

    /**
     * 以下Bean开启shiro权限注解
     *
     * @return DefaultAdvisorAutoProxyCreator
     */
    @Bean
    public static DefaultAdvisorAutoProxyCreator creator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        creator.setProxyTargetClass(true);
        return creator;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager defaultWebSecurityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(defaultWebSecurityManager);
        return authorizationAttributeSourceAdvisor;
    }

    @Bean(name = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }


}